﻿#include "upagination.h"
#include "ulineedit.h"
#include "ulabel.h"
#include "upushbutton.h"

#include <QHBoxLayout>
#include <QSignalMapper>
#include <QButtonGroup>

class UPaginationPrivate
{
public:
    UPaginationPrivate(UPagination* q) : q_ptr(q) {}
    ~UPaginationPrivate() {};

    void init();

    void initConnection();

    void setCurrentPage(int currentPage);

private:
    Q_DECLARE_PUBLIC(UPagination)
    Q_DISABLE_COPY(UPaginationPrivate)
    UPagination* const q_ptr = nullptr;

    int maxPage;
    int currentPage;

    ULabel* leftLabel = nullptr;
    ULabel* label1 = nullptr;
    ULabel* rightLabel = nullptr;

    UPushButton* label = nullptr;
    UPushButton* label2 = nullptr;

    UPushButton* leftBtn = nullptr;
    UPushButton* rightBtn = nullptr;
    UPushButton* firstBtn = nullptr;
    UPushButton* lastbtn = nullptr;
    UPushButton* btn = nullptr;
    UPushButton* btn1 = nullptr;
    UPushButton* btn2 = nullptr;

    ULineEdit* edit = nullptr;
    QButtonGroup* btnGroup = nullptr;
};

void UPaginationPrivate::init()
{
    Q_Q(UPagination);

    leftBtn = new UPushButton(q);
    leftBtn->setIcon(QIcon::fromTheme("left"));
    rightBtn = new UPushButton(q);
    rightBtn->setIcon(QIcon::fromTheme("right"));

    leftLabel = new ULabel(QObject::tr("1 page in total"), q);
    label = new UPushButton(q);
    label->setIcon(QIcon::fromTheme("utk_ellipsis"));
    label2 = new UPushButton(q);
    label2->setIcon(QIcon::fromTheme("utk_ellipsis"));
    label1 = new ULabel(QObject::tr("jump to"), q);
    edit = new ULineEdit(q);
    edit->setFixedWidth(55);
    rightLabel = new ULabel(QObject::tr("page"), q);

    firstBtn = new UPushButton("1", q);
    firstBtn->setCheckable(true);
    btn = new UPushButton(q);
    btn->setCheckable(true);
    btn1 = new UPushButton(q);
    btn1->setCheckable(true);
    btn2 = new UPushButton(q);
    btn2->setCheckable(true);
    lastbtn = new UPushButton(q);
    lastbtn->setCheckable(true);

    btnGroup = new QButtonGroup(q);
    btnGroup->addButton(firstBtn, 0);
    btnGroup->addButton(btn, 1);
    btnGroup->addButton(btn1, 2);
    btnGroup->addButton(btn2, 3);
    btnGroup->addButton(lastbtn, 4);

    QHBoxLayout* mainLayout = new QHBoxLayout();
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->addStretch();
    mainLayout->addWidget(leftLabel);
    mainLayout->addWidget(leftBtn);
    mainLayout->addWidget(firstBtn);
    mainLayout->addWidget(label);
    mainLayout->addWidget(btn);
    mainLayout->addWidget(btn1);
    mainLayout->addWidget(btn2);
    mainLayout->addWidget(label2);
    mainLayout->addWidget(lastbtn);
    mainLayout->addWidget(rightBtn);
    mainLayout->addWidget(label1);
    mainLayout->addWidget(edit);
    mainLayout->addWidget(rightLabel);
    mainLayout->addStretch();

    q->setLayout(mainLayout);

    initConnection();
}

void UPaginationPrivate::initConnection()
{
    Q_Q(UPagination);

    QObject::connect(leftBtn, &UPushButton::clicked, [ = ]()
    {
        setCurrentPage(q->currentPage() - 1);
    });

    QObject::connect(rightBtn, &UPushButton::clicked, [ = ]()
    {
        setCurrentPage(q->currentPage() + 1);
    });

    QObject::connect(edit, &QLineEdit::returnPressed, [ = ]()
    {
        setCurrentPage(edit->text().toInt());
    });

    QSignalMapper* signalMapper = new QSignalMapper(q);
    auto list = btnGroup->buttons();
    for (int i = 0; i < list.size(); i++)
    {
        signalMapper->setMapping(list[i], i);
        QObject::connect(list[i], SIGNAL(clicked()), signalMapper, SLOT(map()));
    }
    QObject::connect(signalMapper, SIGNAL(mapped(int)), q, SLOT(buttonClicked(int)));
}

void UPaginationPrivate::setCurrentPage(int page)
{
    Q_Q(UPagination);
    if (page >= 1)
    {
        q->setCurrentPage(page);
        emit q->currentChange(page);
    }
}

UPagination::UPagination(QWidget* parent) : QWidget(parent)
    , d_ptr(new UPaginationPrivate(this))
{
    Q_D(UPagination);
    d->init();
    setMaxPage(1);
}

UPagination::UPagination(int maxPage, QWidget* parent) : QWidget(parent)
    , d_ptr(new UPaginationPrivate(this))
{
    Q_D(UPagination);
    d->init();
    setMaxPage(maxPage);
}

UPagination::~UPagination()
{
}

void UPagination::setButtonSize(const QSize &size)
{
    auto buttons = findChildren<UPushButton*>();
    for (UPushButton* btn : qAsConst(buttons))
    {
        if (nullptr == btn)
        {
            continue;
        }
        btn->setFixedSize(size);
    }
}

void UPagination::updatePage()
{
    Q_D(UPagination);

    d->label->hide();
    d->label2->hide();

    if (d->maxPage <= 5)
    {
        auto list = d->btnGroup->buttons();
        for (int i = 0; i < list.count(); i++)
        {
            QAbstractButton* button = list.at(i);
            if (i < d->maxPage)
            {
                button->setText(QString::number(i + 1));
                button->show();
            }
            else
            {
                button->hide();
            }
        }
        return;
    }

    if (d->currentPage >= 1 && d->currentPage < 4)
    {
        d->label2->show();
        int num = d->firstBtn->text().toInt();
        d->btn->setText(QString::number(num + 1));
        d->btn1->setText(QString::number(num + 2));
        d->btn2->setText(QString::number(num + 3));
    }
    else if (d->currentPage > d->maxPage - 3 && d->currentPage <= d->maxPage)
    {
        if (d->label2->isVisible())
            d->label2->hide();
        d->label->show();
        d->btn->setText(QString::number(d->maxPage - 3));
        d->btn1->setText(QString::number(d->maxPage - 2));
        d->btn2->setText(QString::number(d->maxPage - 1));
    }
    else
    {
        d->label->show();
        d->label2->show();
        d->btn->setText(QString::number(d->currentPage - 1));
        d->btn1->setText(QString::number(d->currentPage));
        d->btn2->setText(QString::number(d->currentPage + 1));
    }

    d->lastbtn->setText(QString::number(d->maxPage));

    for (const auto &button : d->btnGroup->buttons())
    {
        button->show();
        if (button->text().toInt() == d->currentPage)
        {
            button->setChecked(true);
        }
    }
}

int UPagination::maxPage() const
{
    Q_D(const UPagination);
    return d->maxPage;
}

int UPagination::currentPage() const
{
    Q_D(const UPagination);
    return d->currentPage;
}

void UPagination::setMaxPage(int maxPage)
{
    Q_D(UPagination);
    maxPage = qMax(maxPage, 1);

    if (d->maxPage != maxPage)
    {
        QString text = QObject::tr("%1 page in total").arg(maxPage);
        d->leftLabel->setText(text);
        d->maxPage = maxPage;
        d->currentPage = 1;
        updatePage();
    }
}

void UPagination::setCurrentPage(int currentPage)
{
    Q_D(UPagination);
    currentPage = qMax(currentPage, 1);
    currentPage = qMin(currentPage, d->maxPage);

    d->currentPage = currentPage;
    updatePage();
}

void UPagination::buttonClicked(int index)
{
    Q_D(UPagination);
    if (nullptr == d->btnGroup->button(index))
    {
        return;
    }
    d->edit->clear();
    d->setCurrentPage(d->btnGroup->button(index)->text().toInt());
}
